package com.dswfort.novelSpider

import org.jsoup.HttpStatusException
import java.io.File
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.URI
import java.nio.file.Path
import java.nio.file.Paths

data class Novel(
    val title: String,
    val author: String,
    val introduce: String,
    val chapters: ArrayList<Chapter>,
    val source: String
)

data class Chapter(val title: String, val url: String)

/**
 * 小说下载器
 */
abstract class BaseNovelDownloader(host: String) {
    //protected open var downloadDir: String = ""

    var host: String
        protected set

    /**
     * 换行符
     */
    protected val newline: String = System.lineSeparator()

    init {
        this.host = URI(host).host
    }

    /**
     * 解析章节清单
     * @param novelUrl 小说地址
     * @return 小说信息
     */
    protected abstract fun parseChapters(novelUrl: String): Novel

    /**
     * 解析小说章节
     * @param chapter 章节信息
     * @return 章节内容
     */
    protected abstract fun parseChapter(chapter: Chapter): String

    /**
     * 下载小说
     * @param url 小说地址
     */
    fun beginDownload(url: String) {
        val path = System.getProperty("user.dir")

        // 解析小说集章节清单
        println("开始解析小说信息")
        val novel = parseChapters(url)
        println("完成解析小说信息${newline}书名：${novel.title}，作者：${novel.author}，共${novel.chapters.size}章")
        val downloadDir = Paths.get(path, "download", "${novel.title}_${novel.author}")
        val downloadChaptersDir = downloadDir.resolve("chapters")

        val dir = File(downloadChaptersDir.toString())
        if (!dir.exists()) {
            dir.mkdirs()
        }

        println("下载目录：${downloadDir}")

        // 初始化下载进度
        val chapters = novel.chapters
        val chaptersFile = File(downloadDir.resolve("chapters.tmp").toString())

        val downloadedChapterFiles = ArrayList<String>()
        var nextChapterUrl = ""
        val progressFile = File(downloadDir.resolve("progress.tmp").toString())
        if (progressFile.exists()) {
            nextChapterUrl = progressFile.readText()
        }
        if (nextChapterUrl.isEmpty()) {
            nextChapterUrl = novel.chapters[0].url
            chaptersFile.deleteOnExit()
        } else {
            // 读取已经下载的章节文件
            if (chaptersFile.exists()) {
                val content = chaptersFile.readText()
                val arr = content.split(newline)
                if (arr.isNotEmpty()) {
                    arr.forEach {
                        if (it.isNotEmpty()) {
                            downloadedChapterFiles.add(it)
                        }
                    }
                }
            }
        }

        val nextChapter = chapters.singleOrNull {
            nextChapterUrl == it.url
        }

        var beginChapterIndex = 0
        if (nextChapter != null) {
            beginChapterIndex = chapters.indexOf(nextChapter)
        }

        // 下载
        for (index in beginChapterIndex until chapters.size) {
            //for (chapter in chapters) {
            var tryCount = 0
            var isSuccess = false
            var content = ""
            val chapter = chapters[index]

            // 每章最多尝试解析十五次
            do {
                try {
                    content = this.parseChapter(chapter)
                    isSuccess = true
                } catch (ex: SocketTimeoutException) {
                    println(ex.stackTrace)
                    tryCount++
                } catch (ex: HttpStatusException) {
                    println(ex.stackTrace)
                    tryCount++
                } catch (ex: ConnectException) {
                    println(ex.stackTrace)
                    tryCount++
                }
            } while (!isSuccess && tryCount < 15)

            if (isSuccess) {
                val chapterFile = downloadChaptersDir.resolve("${chapter.title}.txt").toString()
                File(chapterFile).writeText(content)

                // 获取下一章地址
                if (index < chapters.size - 1) {
                    nextChapterUrl = chapters[index + 1].url
                    progressFile.writeText(nextChapterUrl)
                } else {
                    progressFile.deleteOnExit()
                }

                // 在文件中保存已下载的章节
                if (downloadedChapterFiles.isNotEmpty()) {
                    chaptersFile.appendText(newline)
                }
                chaptersFile.appendText(chapter.title)
                // 保存下载章节
                downloadedChapterFiles.add(chapterFile)

                println("${chapter.title} 下载完毕（${index + 1}/${chapters.size}）")
            }
        }

        println("章节下载完毕，开始合并文件")
        combineChapters(novel, downloadedChapterFiles, downloadDir)
        println("文件合并完成")
    }

    /**
     * 合并章节到一个文件中
     * @param novel 小说信息
     * @param chapterFiles 已下载章节
     * @param downloadDir 下载目录
     */
    private fun combineChapters(novel: Novel, chapterFiles: ArrayList<String>, downloadDir: Path) {
        val file = File(downloadDir.resolve(("${novel.title} - ${novel.author}.txt")).toString())

        // 标题、作者
        file.writeText("《${novel.title}》${newline}作者：${novel.author}")
        // 介绍
        file.appendText("${newline}${novel.introduce}${newline}")
        // 来源
        file.appendText("${newline}${novel.source}${newline}")

        // 合并章节
        var chapterIndex = 0
        chapterFiles.forEach {
            val chapterFile = File(it)
            val content = chapterFile.readText()

            file.appendText(newline + newline)
            file.appendText(content)
            chapterIndex++
        }
    }
}
